package com.ruoyi.teaching.service.impl;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.teaching.bo.AddTeachingPlanBo;
import com.ruoyi.teaching.bo.PreviewTeachingPlanBo;
import com.ruoyi.teaching.domain.Classes;
import com.ruoyi.teaching.domain.CourseDesign;
import com.ruoyi.teaching.domain.YaHoliday;
import com.ruoyi.teaching.mapper.ClassesMapper;
import com.ruoyi.teaching.mapper.CourseDesignMapper;
import com.ruoyi.teaching.mapper.YaHolidayMapper;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.ruoyi.teaching.mapper.YaTeachingPlanMapper;
import com.ruoyi.teaching.domain.YaTeachingPlan;
import com.ruoyi.teaching.service.IYaTeachingPlanService;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;

/**
 * 教学计划(课表)Service业务层处理
 *
 * @author ruoyi
 * @date 2024-04-09
 */
@Service
public class YaTeachingPlanServiceImpl implements IYaTeachingPlanService
{
    public static final String CLASS_WORKDAY = "class_workday:";
    public static final String CLASS_SELFDAY = "class_selfday:";
    public static final String CLASS_RESTDAY = "class_restday:";
    @Autowired
    private YaTeachingPlanMapper yaTeachingPlanMapper;
    @Autowired
    private ClassesMapper classesMapper;
    @Autowired
    private CourseDesignMapper courseDesignMapper;
    @Autowired
    private YaHolidayMapper holidayMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 查询教学计划(课表)
     *
     * @param id 教学计划(课表)主键
     * @return 教学计划(课表)
     */
    @Override
    public YaTeachingPlan selectYaTeachingPlanById(Long id)
    {
        return yaTeachingPlanMapper.selectYaTeachingPlanById(id);
    }

    /**
     * 查询教学计划(课表)列表
     *
     * @param yaTeachingPlan 教学计划(课表)
     * @return 教学计划(课表)
     */
    @Override
    public List<YaTeachingPlan> selectYaTeachingPlanList(YaTeachingPlan yaTeachingPlan)
    {
        return yaTeachingPlanMapper.selectYaTeachingPlanList(yaTeachingPlan);
    }

    /**
     * 新增教学计划(课表)
     *
     * @param yaTeachingPlan 教学计划(课表)
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public int insertYaTeachingPlan(AddTeachingPlanBo yaTeachingPlan)
    {
        //1.根据参数删除班级之前的课表
        //TODO 需要考虑到后续已经上课后的内容（不允许删除）
        yaTeachingPlanMapper.delete(new LambdaQueryWrapper<YaTeachingPlan>()
                .eq(YaTeachingPlan::getClassName, yaTeachingPlan.getClassName())
                .eq(YaTeachingPlan::getStage, yaTeachingPlan.getStage())
        );

        //2.批量新增
        List<YaTeachingPlan> teachingPlanList = yaTeachingPlan.getTeachingPlanList();

        return yaTeachingPlanMapper.batchInsertYaTeachingPlan(teachingPlanList);
    }

    /**
     * 修改教学计划(课表)
     *
     * @param yaTeachingPlan 教学计划(课表)
     * @return 结果
     */
    @Override
    public int updateYaTeachingPlan(YaTeachingPlan yaTeachingPlan)
    {
        return yaTeachingPlanMapper.updateYaTeachingPlan(yaTeachingPlan);
    }

    /**
     * 批量删除教学计划(课表)
     *
     * @param ids 需要删除的教学计划(课表)主键
     * @return 结果
     */
    @Override
    public int deleteYaTeachingPlanByIds(Long[] ids)
    {
        return yaTeachingPlanMapper.deleteYaTeachingPlanByIds(ids);
    }

    /**
     * 删除教学计划(课表)信息
     *
     * @param id 教学计划(课表)主键
     * @return 结果
     */
    @Override
    public int deleteYaTeachingPlanById(Long id)
    {
        return yaTeachingPlanMapper.deleteYaTeachingPlanById(id);
    }

    @Override
    public List<YaTeachingPlan> selectTeachingPlanList(Integer stage, String className) {
        return yaTeachingPlanMapper.selectList(new LambdaQueryWrapper<YaTeachingPlan>()
                .eq(YaTeachingPlan::getClassName,className)
                .eq(YaTeachingPlan::getStage,stage)
        );
    }

    @Override
    @Transactional(readOnly = true)
    public List<YaTeachingPlan> previewTeachingPlan(PreviewTeachingPlanBo previewTeachingPlanBo) {
        //根据班级名字查询到班级信息（休息日，自习日）
        Classes classes = classesMapper.selectOne(new LambdaQueryWrapper<Classes>().eq(Classes::getClassName, previewTeachingPlanBo.getClassName()));
        //班级正常休息日
        Integer restDay = classes.getRestDay();
        //班级正常自习日
        Integer selfStudyDay = classes.getSelfStudyDay();
        if (ObjectUtils.isEmpty(classes)) {
            throw new ServiceException("班级不存在");
        }
        //根据阶段查询课程设计列表
        List<CourseDesign> courseDesignList = courseDesignMapper.selectList(new LambdaQueryWrapper<CourseDesign>().eq(CourseDesign::getStage, previewTeachingPlanBo.getStage()));

        //根据起始日期查询出对应的节假日
        Map<String,String> holidayMaps = holidayMapper.selectYaHolidayByBeginDate(previewTeachingPlanBo.getBeginDate())
                .stream()
                .collect(Collectors.toMap(YaHoliday::getDate,YaHoliday::getDescription));

        //从redis中查询出班级特有上课日，自习日，休息日
        Map<Object, Object> workDayMap = stringRedisTemplate.opsForHash().entries(CLASS_WORKDAY +classes.getId());
        Map<Object, Object> selfDayMap = stringRedisTemplate.opsForHash().entries(CLASS_SELFDAY +classes.getId());
        Map<Object, Object> restDayMap = stringRedisTemplate.opsForHash().entries(CLASS_RESTDAY +classes.getId());
        int  day = 1;
        String beginDate = previewTeachingPlanBo.getBeginDate();
        LocalDate currentDate = LocalDate.parse(beginDate);
        //教学计划列表
        List<YaTeachingPlan> result = new ArrayList<>();
        while (true) {
            beginDate = currentDate.toString();
            YaTeachingPlan tp = new YaTeachingPlan();
            //判断当前日期是否国家法定节假日
            if (holidayMaps.containsKey(beginDate)) {
                tp.setCourseContent(holidayMaps.get(beginDate));
            }
            //判断是否班级特殊自习/休息
            else if (selfDayMap.containsKey(beginDate)) {
                tp.setCourseContent(selfDayMap.get(beginDate).toString());
            }
            else if (restDayMap.containsKey(beginDate)) {
                tp.setCourseContent(restDayMap.get(beginDate).toString());
            }
            //判断是否班级正常自习/休息  && 不在班级特殊上课日中
            else if (currentDate.getDayOfWeek().getValue() == selfStudyDay && !workDayMap.containsKey(beginDate)) {
                tp.setCourseContent("自习");
            } else if (currentDate.getDayOfWeek().getValue() == restDay && !workDayMap.containsKey(beginDate)) {
                tp.setCourseContent("休息");
            } else {
                //正常排课
                CourseDesign courseDesign = courseDesignList.get(day - 1);
                tp.setCourseContent(courseDesign.getCourseContent());
                tp.setDay(Long.valueOf(day));
                tp.setCourseDesignId(courseDesign.getId());
                day++;
            }
            tp.setDate(beginDate);
            tp.setClassName(previewTeachingPlanBo.getClassName());
            tp.setStage(previewTeachingPlanBo.getStage());
            tp.setClassesId(classes.getId());
            tp.setWeekday(currentDate.getDayOfWeek().getValue());

            result.add(tp);
            //自增日期
            currentDate = currentDate.plusDays(1);
            //判断是否是最后一天
            if (day > courseDesignList.size()) {
                break;
            }
        }
        return result;
    }

    @Override
    public void addWorkday(PreviewTeachingPlanBo previewTeachingPlanBo) {
        //获取当前日期
        String date = previewTeachingPlanBo.getDate();
        Long classesId = previewTeachingPlanBo.getClassesId();
        //保存到班级特有工作日中
        stringRedisTemplate.opsForHash().put(CLASS_WORKDAY+classesId,date,"上课");
        //清除班级特殊自习日&休息日
        stringRedisTemplate.opsForHash().delete(CLASS_SELFDAY + classesId, date);
        stringRedisTemplate.opsForHash().delete(CLASS_RESTDAY + classesId, date);
    }


    @Override
    public void addHoliday(PreviewTeachingPlanBo previewTeachingPlanBo) {
        //获取当前日期
        String date = previewTeachingPlanBo.getDate();
        Long classesId = previewTeachingPlanBo.getClassesId();
        //保存到班级特有工作日中
        stringRedisTemplate.opsForHash().delete(CLASS_WORKDAY+classesId,date);
        //清除班级特殊自习日&休息日
        String type = previewTeachingPlanBo.getType();
        if ("休息".equals(type)) {
            stringRedisTemplate.opsForHash().put(CLASS_RESTDAY + classesId, date, "休息");
            stringRedisTemplate.opsForHash().delete(CLASS_SELFDAY + classesId, date);
        } else {
            stringRedisTemplate.opsForHash().put(CLASS_SELFDAY + classesId, date, "自习");
            stringRedisTemplate.opsForHash().delete(CLASS_RESTDAY + classesId, date);
        }
    }
}
